home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
TTYDRIV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-28
|
9KB
|
381 lines
/* TTY input driver */
#include <stdio.h>
#include <ctype.h>
#include "global.h"
int ttymode;
#define TTY_COOKED 0
#define TTY_RAW 1
#define LINESIZE 256
#define MAXHIST 25
#define CTLR 18
#define CTLX 24
#define CTLU 21
#define CTLV 22
#define CTLW 23
#define CTLZ 26
struct linehist
{
struct linehist *next;
struct linehist *prev;
char linebuf[1];
};
#define NULLHIST (struct linehist *)0
struct linehist *linehist = NULLHIST;
raw()
{
ttymode = TTY_RAW;
}
cooked()
{
ttymode = TTY_COOKED;
}
static void echochar (c) /* echo character */
unsigned char c;
{
if (c < ' ') { /* a control char? */
putchar('^'); /* show as ^char */
c += 64;
}
putchar(c);
}
static void bschar (c) /* backspace over character */
unsigned char c;
{
if (c < ' ') /* a control char? */
putchar('\b'); /* 2 backspaces needed */
putchar('\b');
}
static void erachar (c) /* erase character */
unsigned char c;
{
if (c < ' ') /* a control char? */
putchar(' '); /* 2 spaces needed */
putchar(' ');
if (c < ' ') /* a control char? */
putchar('\b'); /* 2 backspaces needed */
putchar('\b');
}
/* Accept characters from the incoming tty buffer and process them
* (if in cooked mode) or just pass them directly (if in raw mode).
* Returns the number of characters available for use; if non-zero,
* also stashes a pointer to the character(s) in the "buf" argument.
*/
/*Control-R added by df for retype of lines - useful in Telnet */
/* full editing and history added by PE1CHL */
int
ttydriv(c,buf)
int c;
char **buf;
{
static char linebuf[LINESIZE + 1];
static char *cp = linebuf;
static struct linehist *lh = NULLHIST;
static char insmode = 0;
static char quote = 0;
static int tailchars = 0;
register char *p,*q;
int cnt,i,seenprint;
if(c == -1) /* -1 is used to inquire buffered chars */
return((int) (cp - linebuf) + tailchars);
#ifdef DEBUG
if(buf == (char **)NULL)
return 0; /* paranoia check */
#endif
/* initialize buffer when 1st call for this line */
if(cp == linebuf && !tailchars){
memset(linebuf,0,LINESIZE);
if((lh = linehist) != NULLHIST)
strcpy(linebuf,lh->linebuf);
}
cnt = 0;
switch(ttymode){
case TTY_RAW:
tailchars = 0; /* clear the COOKED line buffer */
insmode = quote = 0;
cp = linebuf;
switch(c){
case -20: /* HOME key */
strcpy(linebuf,"\033[H");
cp += 3;
break;
case -19: /* UP arrow */
strcpy(linebuf,"\033[A");
cp += 3;
break;
case -17: /* LEFT arrow */
strcpy(linebuf,"\033[D");
cp += 3;
break;
case -16: /* RIGHT arrow */
strcpy(linebuf,"\033[C");
cp += 3;
break;
case -14: /* DOWN arrow */
strcpy(linebuf,"\033[B");
cp += 3;
break;
default: /* a normal character */
*cp++ = c;
break;
}
cnt = (int) (cp - linebuf); /* return count of characters */
break;
case TTY_COOKED:
/* Perform cooked-mode line editing */
if (quote) /* prev char was quote? (^V) */
goto storechar; /* then store anything */
switch(c){
case '\r': /* CR and LF are equivalent */
case '\n':
while(tailchars > 0){ /* move to end of line */
echochar(*cp++);
tailchars--;
}
*cp++ = '\r';
*cp++ = '\n';
*cp = '\0';
printf("\n");
cnt = (int) (cp - linebuf);
cp = linebuf;
if(cnt > 3){
i = 0;
for(lh = linehist; lh != NULLHIST; lh = lh->next){
if(!strcmp(lh->linebuf,linebuf) || ++i > MAXHIST){
if(lh->prev != NULLHIST)
lh->prev->next = lh->next;
else
linehist = lh->next;
if(lh->next != NULLHIST)
lh->next->prev = lh->prev;
free(lh);
}
}
if((lh = (struct linehist *) malloc(sizeof(struct linehist) + cnt)) != NULLHIST){
if((lh->next = linehist) != NULLHIST)
lh->next->prev = lh;
lh->prev = NULLHIST;
linehist = lh;
strcpy(lh->linebuf,linebuf);
}
}
insmode = 0;
break;
case 0x7f: /* Delete */
if (tailchars > 0){
tailchars--;
c = *cp;
for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
echochar(p[1]);
*p++ = *q++;
}
erachar(c);
*p = '\0';
for(i = 0; i < tailchars; i++)
bschar(*--p);
} else {
goto storechar;
}
break;
case '\b': /* Backspace */
if(cp != linebuf){
bschar(c = *--cp);
for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
echochar(p[1]);
*p++ = *q++;
}
erachar(c);
*p = '\0';
for(i = 0; i < tailchars; i++)
bschar(*--p);
}
break;
case CTLR: /* print line buffer */
echochar(c); /* ^R */
putchar('\n');
p = linebuf;
cp += tailchars;
while(p < cp)
echochar(*p++);
tailchars = 0;
break;
case CTLU: /* Line kill */
case CTLX: /* Also a line kill */
while(tailchars > 0){
echochar(*cp++);
tailchars--;
}
while(cp != linebuf){
bschar(*--cp);
erachar(*cp);
}
break;
case CTLV: /* Literal Next */
quote = 1;
c = '^'; /* insert a ^ temporarily */
goto storechar;
case CTLW: /* Word Erase */
seenprint = 0; /* Haven't seen a printable char yet */
while(cp != linebuf){
if (!isspace(cp[-1])) /* Next is a printable char? */
seenprint = 1;
else
if (seenprint) /* Next is a space, quit when we */
break; /* already erased characters */
bschar(c = *--cp);
for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
echochar(p[1]);
*p++ = *q++;
}
erachar(c);
*p = '\0';
for(i = 0; i < tailchars; i++)
bschar(*--p);
}
break;
case -14: /* down-arrow = next in history */
if(lh != NULLHIST && lh->prev != NULLHIST){
lh = lh->prev;
while(tailchars > 0){ /* move to end of line */
echochar(*cp++);
tailchars--;
}
while(cp != linebuf){ /* erase it */
bschar(*--cp);
erachar(*cp);
}
memset(linebuf,0,LINESIZE);
strcpy(linebuf,lh->linebuf);
for(cp = linebuf; *cp && *cp != '\r'; cp++){
echochar(*cp);
}
}
break;
case -12: /* insert */
insmode ^= 1; /* toggle insert mode */
break;
case -16: /* right-arrow = buffer character */
insmode = 0; /* insert mode screws things up */
if(*cp && *cp != '\r'){
c = *cp;
goto storechar;
}
break;
case -17: /* left-arrow = nondestruct backspace */
if(cp != linebuf){
tailchars++;
bschar(*--cp);
}
break;
case -19: /* up-arrow = prev in history */
if(lh != NULLHIST){
while(tailchars > 0){ /* move to end of line */
echochar(*cp++);
tailchars--;
}
while(cp != linebuf){ /* erase it */
bschar(*--cp);
erachar(*cp);
}
memset(linebuf,0,LINESIZE);
strcpy(linebuf,lh->linebuf);
if (lh->next != NULLHIST)
lh = lh->next;
for(cp = linebuf; *cp && *cp != '\r'; cp++)
echochar(*cp);
}
break;
case -20: /* HOME = begin of line */
while(cp != linebuf){
tailchars++;
bschar(*--cp);
}
break;
case -15: /* END = end of line */
while(tailchars > 0){
echochar(*cp++);
tailchars--;
}
break;
default: /* Ordinary character */
if(c < 0) /* a non-decoded special character? */
break; /* ignore it */
storechar:
echochar(c);
if(insmode && quote < 2){
for(i = 0, p = cp; i < tailchars; i++)
echochar(*p++);
for(i = 0, q = p + 1; i < tailchars; i++)
bschar(*--q = *--p);
} else {
if(tailchars > 0){
tailchars--;
if(c < ' ' || *cp < ' '){
for(i = 0, p = cp + 1; i < tailchars; i++)
echochar(*p++);
erachar(' ');
for(i = 0; i < tailchars; i++)
bschar(*--p);
}
}
}
if(quote)
if(quote == 1){ /* immediately after ^V */
quote = 2;
bschar(c); /* backspace to the '^' */